package com.baidu.encrypt.common.utils;

import com.baidu.sggc.entity.vo.FsVo;

import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.UUID;

@Slf4j
@Service
public class MinioEncryptService {

    private final MinioClient minioClient;

    @Autowired
    private SM4Util sm4Util;

    @Value("${minio.bucket-name}")
    private String bucketName;

    public MinioEncryptService(
            MinioClient minioClient,
            @Value("${sm4.key}") String sm4Key,
            @Value("${sm4.iv}") String sm4Iv) {
        this.minioClient = minioClient;
    }

    @PostConstruct
    public void initBucket() {
        try {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                log.info("MinIO bucket '{}' created", bucketName);
            }
        } catch (Exception e) {
            throw new RuntimeException("初始化 MinIO 存储桶失败", e);
        }
    }

    /** 加密上传 */
    public FsVo uploadEncrypted(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        String objectName = System.currentTimeMillis() + "_" + UUID.randomUUID() + ".enc";

        try (InputStream in = file.getInputStream();
             PipedOutputStream pipedOut = new PipedOutputStream();
             PipedInputStream pipedIn = new PipedInputStream(pipedOut)) {

            // 启动加密线程（边读边加密）
            new Thread(() -> {
                try {
                    sm4Util.encryptStream(in, pipedOut);
                } catch (Exception e) {
                    log.error("加密过程出错", e);
                } finally {
                    try {
                        pipedOut.close();
                    } catch (IOException ignore) {}
                }
            }).start();

            // 上传加密流
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(pipedIn, -1, 5 * 1024 * 1024) // 分片5MB
                            .contentType("application/octet-stream")
                            .build()
            );

            FsVo fsVo = new FsVo();
            fsVo.setObject(objectName);
            fsVo.setFileName(originalFilename);
            fsVo.setFileSize(file.getSize());
            fsVo.setFileType(file.getContentType());
            return fsVo;

        } catch (Exception e) {
            throw new RuntimeException("加密上传失败", e);
        }
    }

    /** 解密下载 */
    public void downloadAndDecrypt(String objectName, OutputStream out) {
        try (InputStream minioStream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build())) {

            sm4Util.decryptStream(minioStream, out);

        } catch (Exception e) {
            throw new RuntimeException("解密下载失败", e);
        }
    }
}
